package lode

import (
	"io"
	"os"
	"path/filepath"
	"strings"
	"syscall"
	"time"
)

func CopyDir(src, dst string) error {
	mask := syscall.Umask(0)
	defer syscall.Umask(mask)
	if err := CreateIfNotExists(dst, 0700);  err != nil {
		return err
	}
	return filepath.Walk(src, func(file string, fi os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		pathInSrc := strings.TrimPrefix(strings.Replace(file, src,"" , -1), string(filepath.Separator))
		dstPath := filepath.Join(dst, pathInSrc)
		switch fi.Mode() & os.ModeType{
		case os.ModeDir:
			if err := CreateIfNotExists(dstPath, fi.Mode()); err != nil {
				return err
			}
		case os.ModeSymlink:
			if err := CopySymLink(file, dstPath, fi); err != nil {
				return err
			}
		default:
			if err := Copy(file, dstPath, fi); err != nil {
				return err
			}
		}
		return correctTime(dstPath, fi)
	})
}

func Copy(srcFile, dstFile string, info os.FileInfo) error {
	out, err := os.Create(dstFile)
	if err != nil {
		return err
	}

	defer out.Close()

	in, err := os.Open(srcFile)
	defer in.Close()
	if err != nil {
		return err
	}

	_, err = io.Copy(out, in)
	if err != nil {
		return err
	}
	return nil
}

func CopySymLink(source, dst string, info os.FileInfo) error {
	link, err := os.Readlink(source)
	if err != nil {
		return err
	}
	return os.Symlink(link, dst)
}

func correctTime(dst string, info os.FileInfo) error {
	stat := info.Sys().(*syscall.Stat_t)
	aTime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
	return os.Chtimes(dst, aTime, info.ModTime())
}
